if RUBY_VERSION < '1.9'
  puts "This application needs ruby 1.9 or higher to run!"
  exit 1
end

require 'sinatra'
require 'open-uri'
require 'zlib'
require 'json'
require 'yaml'


Encoding.default_external = Encoding::UTF_8
use Rack::Logger

PBAPI_BASE_URL = "http://demo.places.nlp.nokia.com/places/v1"
CREDENTIALS = "app_id=demo_qCG24t50dHOwrLQ&app_code=NYKC67ShPhQwqaydGIW4yg"

CITIES = {
  "francisco" => {:name => "San Francisco", :viewport => [-122.5421,37.6765,-122.2674,37.8936]},
  "berlin" =>    {:name => "Berlin",        :viewport => [ 13.088,  52.338,   13.761,  52.675]},
  "london" =>    {:name => "London",        :viewport => [ -0.348,  51.385,    0.140,  51.667]},
  "newyork" =>   {:name => "New York", :viewport => [-74.255,  40.497, -73.700,  40.912]}
}

helpers do
  include Rack::Utils

  alias_method :h, :escape_html

  def logger
    request.logger
  end

  def encode_url(url)
    URI::encode(url, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
  end

  def backend_url(url_type, pbapi_url)
    "/#{url_type}?backend_url=#{encode_url(pbapi_url)}"
  end

  def decode_pbapi_url()
    params['backend_url'] || ""
  end

  def open_gzip(url, headers)
    config = YAML.load(File.new('config.yaml'))
    proxy = config ? config["proxy_address_and_port"] : nil
    headers[:proxy] = proxy
    Zlib::GzipReader.new(open(url, headers))
  end

  def fetch_parsed_pbapi_response(url, headers={})
    standard_headers = {
      "Accept" => "application/json",
      "Accept-Language" => request.env["HTTP_ACCEPT_LANGUAGE"],
      "Accept-Encoding" => "gzip"
    }
    logger.info("Fetching url: #{url}")
    logger.info("Headers: #{standard_headers.merge(headers).inspect}")
    JSON.parse(open_gzip(url, standard_headers.merge(headers)).read)
  end

  def fetch_explore_results_for(viewport)
    explore_url = "#{PBAPI_BASE_URL}/discover/explore?#{CREDENTIALS}"
    viewport_header = {"X-Map-Viewport" => viewport.join(",")}
    fetch_parsed_pbapi_response(explore_url, viewport_header)
  end

  def fetch_search_results_for(query, viewport_string)
    search_url = "#{PBAPI_BASE_URL}/discover/search?#{CREDENTIALS}&q=#{URI.escape(query)}"
    viewport_header = {"X-Map-Viewport" => viewport_string}
    fetch_parsed_pbapi_response(search_url, viewport_header)
  end

  def fetch_place(place_url)
    fetch_parsed_pbapi_response(place_url + "&image_dimensions=w64-h64")
  end

  def recommendations_from(place)
    fetch_parsed_pbapi_response(place['related']['recommended']['href'])
  end

  def extract_search_results_from(response)
    results = response['results']['items']
    results.select {|result| result['type'] == "urn:nlp-types:place"}
  end
end

get '/' do
  @cities = CITIES
  erb :choose
end

get '/city/:city' do |city_name|
  @city = CITIES[city_name]

  explore_response = fetch_explore_results_for(@city[:viewport])
  @places = extract_search_results_from(explore_response)

  @pbapi_base_url = PBAPI_BASE_URL
  @pbapi_credentials = CREDENTIALS

  erb :map
end

get '/search' do
  query = params["q"]
  viewport = params["viewport"]

  search_response = fetch_search_results_for(query, viewport)
  @places = extract_search_results_from(search_response)

  erb :map_data, :locals => {:places => @places}
end

get '/place' do
  url_to_place = decode_pbapi_url()

  @place = fetch_place(url_to_place)
  @recommendations = recommendations_from(@place)

  erb :place
end

get '/images' do
  next_images_url = decode_pbapi_url()

  next_images = fetch_parsed_pbapi_response(next_images_url)

  erb :images, :locals => {:images => next_images}
end

get '/reviews' do
  next_reviews_url = decode_pbapi_url()

  next_reviews = fetch_parsed_pbapi_response(next_reviews_url)

  erb :reviews, :locals => {:reviews => next_reviews}
end
